package com.adee.java;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.List;
import java.util.Map;

/**
 * 在JDK1.5之前之一原始类型。此时，所有的原始类型都通过字节码文件类Class进行抽象。Class类的一个具体对象就代表一个指定的原始类型。
 * JDK1.5加入了泛型类，扩充了数据类型，从只有原始类型基础上扩充了 参数化类型、类型变量类型、通配符类型、泛型数组类型。
 * Type是Java语言中所有类型（Class）的公共父接口。
 *
 * 从做到右依次是：Class（原始/基本类型）：实现了Type接口，GenericArrayType（泛型数组类型），ParameterizedType（参数化类型），
 * WildcardType（通配符类型），TypeVariable（类型变量）。
 *
 * Class：不仅包括我们平常所指的类、枚举、数组、注解，还包括基本类型int、float等等。
 * TypeVariable：比如List 中的T等。
 * WildcardType：也叫做泛型表达式类型，例如List<? extends Number> 这种。
 * ParameterizedType：就是我们平常所用到的泛型List、Map（注意和TypeVariable的区别，参数化类型表示的是List这样的一个整体而不是T）。
 * GenericArrayType：泛型数组类型，并不是我们工作中所使用的数组String[]、Byte[]，这些都是Class，而是带有泛型的数组，即T[]。
 * Type接口本身算是一个标记接口，不提供任何需要复写的方法。
 *
 * ParameterizedType 参数化类型
 * 参数化类型，即平常用的泛型；例如：List、Map<K,V>等带有参数化的对象。
 * 如何理解呢？
 * 一提到参数，最熟悉的就是定义方法时有形参，然后调用此方法时传递实参。那么参数化类型怎么理解呢？顾名思义，就是将类型由原来的具体的
 * 类型参数化（比如：List，T就是类型参数），类似于方法中的参数变量，此时类型也定义成参数形式（可以称之为类型形参），然后在使用/调用
 * 时传入具体的类型（类型实参）。
 *
 * public interface ParameterizedType extends Type {
 *  	// 获取类型内部的参数化类型，比如Map<K,V>里面的K,V类型;
 *  	// 注意该方法只返回最外层的<>中的类型，无论该<>内有多少个<>。
 *     Type[] getActualTypeArguments();
 *  	// 类的原始类型，一般都是Class
 *     Type getRawType();
 * 	// 获取所有者类型（只有内部类才有所有者，比如Map.Entry的所有者就是Map）,如果不是内部类，返回null。
 *     Type getOwnerType();
 * }
 *
 *
 *
 */
@Slf4j
public class Test034_ParameterizedType {
    public static void main(String[] args) throws Exception {

         test1();
        // test2();

    }

    // 获取字段的原始类型及所有泛型类型
    public static void test1() {
        /**
         * 1、getFields：获取当前类或父类或父接口的 public 修饰的字段。
         * 2、getDeclaredFields：获取当前类的所有字段，包括 protected/默认/private
         * 修饰的字段；不包括父类public 修饰的字段。
         */
        Field[] fields = Entity.class.getDeclaredFields();
        // fields = null;
        for (Field f : fields) {
            System.out.printf("字段[%s]是否为泛型：%s，原始类型：%s，泛型类型：%s",
                    f.getName(),
                    f.getGenericType() instanceof ParameterizedType,
                    f.getType().getName(),
                    f.getGenericType().getTypeName());
            Type genericType = f.getGenericType();
            if(genericType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericType;
                System.out.printf("，泛型参数类型：<");
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                for (int i = 0; i < actualTypeArguments.length; i++) {
                    System.out.printf("%s", actualTypeArguments[i].getTypeName());
                    if(i == actualTypeArguments.length-1) {
                        System.out.printf(">");
                    }else {
                        System.out.printf(", ");
                    }
                }
            }
            System.out.println();
        }
    }

    // 获取class的原始类型和父类原始类型，及父类泛型
    public static void test2() {
        String name = Student.class.getName();
        TypeVariable<Class<Student>>[] typeParameters = Student.class.getTypeParameters();
        Type[] genericInterfaces = Student.class.getGenericInterfaces();
        Type genericSuperclass = Student.class.getGenericSuperclass();
        System.out.printf("类[%s]是否为泛型类：%s,", name,
                typeParameters.length>0);
    }

    static class Entity {
        List<Integer> list;
        Map<String, List<String[]>> map;
        Entity[] arr;
        String str;
        List lst; // 没指定类型参数，不是ParameterizedType
    }

    static class Person<T,E> {

    }


    static class Student<T> extends Person<Student,Integer>   {

    }
}
